<template>
  <div class="profile-header-avatar">
    <div class="user-avatar">
      <img :src="user.avatar" alt="用户头像" class="user-avatar-img">
    </div>
    <template v-if="user.id === curUser.id">
      <label class="upload-picture-wrapper">
        <input
          type="file"
          :accept="accept.types.toString()"
          hidden
          ref="fileInput"
          @change="fileChange"
        >
        <div class="mask user-avatar-editor-mask" :class="{ 'mask-hidden': maskHidden }">
          <div class="mask-mask mask-mask--black user-avatar-editor-mask-inner"></div>
          <div class="mask-content">
            <svg-icon icon-name="cameraIcon" class="s36" />
            <div class="line1">修改我的头像</div>
          </div>
        </div>
      </label>
      <el-dialog
        title="图片裁剪"
        :visible.sync="cropVisible"
        :close-on-click-modal="false"
        @open="dialogOpen"
      >
        <div class="flex">
          <div class="flex-2">
            <vue-cropper
              ref="cropper"
              :src="imageSrc"
              :view-mode="1"
              :initial-aspect-ratio="1"
              :aspect-ratio="1"
              preview=".preview-box"
            />
            <div class="m-t-10 text-center">
              <el-button-group>
                <el-button
                  icon="el-icon-zoom-in"
                  class="button button--primary button--blue"
                  @click="zoom(0.2)"/>
                <el-button
                  icon="el-icon-zoom-out"
                  class="button button--primary button--blue"
                  @click="zoom(-0.2)" />
              </el-button-group>
              <el-button-group>
                <el-button
                  icon="el-icon-refresh-left"
                  class="button button--primary button--blue"
                  @click="rotate(-15)" />
                <el-button
                  icon="el-icon-refresh-right"
                  class="button button--primary button--blue"
                  @click="rotate(15)" />
              </el-button-group>
            </div>
          </div>
          <div class="flex-1 m-l-16 flex direction-column align-items-center">
            <div class="preview-box el-avatar el-avatar--circle s90"></div>
            <div class="m-t-16 flex content-space-between">
              <el-button
                class="button button--primary button--blue"
                @click="crop"
                :loading="loading"
              >确定</el-button>
              <el-button class="button button--grey el-button--default" @click="cancel">
                取消
              </el-button>
            </div>
          </div>
        </div>
      </el-dialog>
    </template>
  </div>
</template>

<script>
import { mapState, mapActions } from 'vuex';
// eslint-disable-next-line import/no-extraneous-dependencies
import 'cropperjs/dist/cropper.css';
import VueCropper from 'vue-cropperjs';
import { formatUser } from '@/views/users/format';

export default {
  name: 'profile-header-avatar',
  components: { VueCropper },
  props: {
    user: Object,
    maskHidden: Boolean,
    accept: {
      type: Object,
      default: () => ({ types: ['image/jpg', 'image/jpeg', 'image/png'], msg: '仅支持 jpg, jpeg, png 格式的图片类型' }),
    },
    limitSize: { // 单位 Byte，默认2M
      type: Number,
      default: 2097152,
    },
  },
  data() {
    return {
      cropVisible: false, // 图片裁剪区域的可见性
      imageSrc: '', // 选中图片的base64
      loading: false,
      filename: '',
    };
  },
  computed: {
    ...mapState({ curUser: 'currentUser' }),
    // 大小限制
    limitSizeFixed() {
      let size = this.limitSize;
      if (size < 1024) return `${size}B`;
      size /= 1024;
      if (size < 1024) return `${size}KB`;
      size /= 1024;
      return `${size}MB`;
    },
  },
  methods: {
    ...mapActions({ setCurUser: 'setCurrentUser' }),
    // 选中了文件
    fileChange() {
      const file = this.$refs.fileInput.files[0];
      if (!this.accept.types.includes(file.type)) { // 判断选中的文件类型
        this.$message.error(this.accept.msg);
        this.$refs.fileInput.value = '';
      } else if (file.size > this.limitSize) { // 判断选中图片的大小
        this.$message.error(`请选择小于 ${this.limitSizeFixed} 的图片`);
        this.$refs.fileInput.value = '';
      } else {
        this.filename = file.name;
        const fr = new FileReader();
        fr.readAsDataURL(file);
        fr.onload = (e) => {
          this.imageSrc = e.target.result;
          this.cropVisible = true;
          this.$refs.fileInput.value = '';
        };
      }
    },
    // 确定裁剪
    async crop() {
      this.loading = true;
      const uploadToken = await this.getUploadToken();
      this.$refs.cropper.getCroppedCanvas().toBlob((blob) => {
        const formData = new FormData();
        formData.append('file', blob);
        formData.append('key', `crop-avatar-${new Date().getTime()}/${this.filename}`);
        formData.append('x:user_id', this.curUser.id);
        formData.append('token', uploadToken);
        this.$api.other.upload(formData)
          .then(res => this.updateUser(res))
          .catch(() => { this.loading = false; });
      });
    },
    // 上传裁剪后的头像
    updateUser({ key, url }) {
      this.loading = true;
      this.$api.users.update({
        userId: this.curUser.id,
        avatarKey: key,
      }).then((res) => {
        this.$message.success('修改成功');
        this.$emit('updatedAvatar', url);
        this.setCurUser(Object.assign(formatUser(res.data), { token: this.curUser.token }));
      }).catch(() => {})
        .then(() => {
          this.cropVisible = false;
          this.loading = false;
        });
    },
    // 打开dialog
    dialogOpen() { if (this.$refs.cropper) this.$refs.cropper.replace(this.imageSrc); },
    // 图片缩放
    zoom(num) { this.$refs.cropper.relativeZoom(num); },
    // 图片旋转
    rotate(deg) { this.$refs.cropper.rotate(deg); },
    // 取消裁剪
    cancel() { this.cropVisible = false; },
    // 获取上传密钥
    getUploadToken() {
      return new Promise((resolve, reject) => {
        this.$api.other.uploadToken()
          .then(res => resolve(res.data.token))
          .catch((err) => {
            this.$message.error('获取上传密钥失败', err);
            this.isLoading = false;
            reject(err);
          });
      });
    },
  },
};
</script>

<style lang="scss">
.mask {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: 1;
  transition: opacity .2s ease-in;

  :focus { outline: 0; }
}
.mask-hidden {
  /*pointer-events: none;*/
  opacity: 0;
}
.mask.mask-hidden:hover {
  opacity: 1;
}
.mask-mask {
  position: absolute;
  width: 100%;
  height: 100%;
  opacity: .4;
  box-sizing: border-box;
}
.user-avatar-editor-mask-inner {
  z-index: 4;
  border: 4px solid #fff;
  border-radius: 50%;
}
.mask-mask--black {
  background-color: #121212;
}
.mask-content {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 5;
  color: #fff;
  text-align: center;
  transform: translate(-50%, -50%);
}
</style>
